package com.shikx.demo.janino.compiler;

import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.util.ResourceFinderClassLoader;
import org.codehaus.commons.compiler.util.resource.MapResourceCreator;
import org.codehaus.commons.compiler.util.resource.MapResourceFinder;
import org.codehaus.commons.compiler.util.resource.Resource;
import org.codehaus.commons.compiler.util.resource.StringResource;
import org.codehaus.janino.ClassLoaderIClassLoader;
import org.codehaus.janino.Compiler;
import org.codehaus.janino.CompilerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Kaixuan Shi
 * @since 2023/7/17
 */
public class CompileService {

    private static final CompilerFactory compilerFactory = new CompilerFactory();

    public void compile(List<JavaSourceCode> sourceCodes) {
        Compiler compiler = (Compiler) compilerFactory.newCompiler();
        Map<String, byte[]> classes = new HashMap<>();
        compiler.setClassFileCreator(new MapResourceCreator(classes));
        compiler.setIClassLoader(new ClassLoaderIClassLoader(CompileService.class.getClassLoader()));
        Resource[] resources = new Resource[sourceCodes.size()];
        for (int i = 0; i < sourceCodes.size(); i++) {
            JavaSourceCode sourceCode = sourceCodes.get(i);
            resources[i] = new StringResource(sourceCode.getFullClassName(), sourceCode.getSourceCode());
        }

        // 调用Janino编译服务
        try {
            compiler.compile(resources);
        } catch (CompileException | IOException e) {
            throw new RuntimeException(e);
        }

        // 将编译后的字节码class赋给ClassLoader，以使用此ClassLoader加载类
        ClassLoader cl = new ResourceFinderClassLoader(
                new MapResourceFinder(classes),
                CompileService.class.getClassLoader()
        );
        ClassLoaderService.setClassLoader(cl);
    }
}
